import datetime
import functools
import logging
import signal
import os

from enum import Enum
from collections import deque
from threading import Timer

from absl import app, flags
from tornado.ioloop import PeriodicCallback

from coin.base.datetime_util import to_datetime
from coin.base.timestamp import get_timestamp
from coin.base.param_util import to_list
from coin.exchange.base.order_gateway_config import convert_og_config_from_dict
from coin.exchange.base.strategy_logger import StrategyLogProvider
from coin.exchange.kr_rest.product.product_impl import (generate_product_from_subreq)
from coin.exchange.kr_rest.product_holders import get_holder_from_product
from coin.exchange.util.feed_checker import get_default_feed_checker_config
from coin.proto.coin_feed_pb2 import BestBookEntry, BookEntry
from coin.proto.coin_request_pb2 import AccountRequestProto
from coin.proto.coin_telemetry_pb2 import LatencyProto

from coin.strategy.accounting.pnl_balance_printer.util import (get_quote_currency, reserve_as_proto)
from coin.strategy.executor.aggressive.util import (convert_executor_config_from_dict)
from coin.strategy.executor.aggressive.factory import construct_agg_executor
from coin.strategy.executor.util.cancel_all_executor import (SimpleCancelAllExecutor)
from coin.strategy.hk_hard_arb.index_pricer import IndexPricer
from coin.strategy.hk_hard_arb.pricer import PositionLeanPricer
from coin.strategy.hk_hard_arb.util import load_clean_json
from coin.strategy.mm.base.bookmap import BookMap
from coin.strategy.mm.base.unary_multifeed_strategy_base import UnaryMultifeedStrategyBase

from coin.strategy.mm.subscription import (
    FeedSubscriptionRequest,
    SubscriptionRequest,
)
from coin.strategy.tool.fill_log_dumper import FillLogDumper
from coin.strategy.hk_hard_arb.amplitude_checker import AmplitudeChecker
from coin.strategy.accounting.pnl_balance_printer.factory import get_pnl_balance_printer_cls
from coin.strategy.util.request_util import convert_strategy_request_from_dict
from coin.support.telemetry.latency_recorder import LatencyRecorder, LifeOfSignal
from coin.strategy.hk_hard_arb.unhedged_mm_3 import (
    PassUnhedgeStrategyConfig,
)
from coin.exchange.base.order_gateway import OrderSide
from coin.exchange.base.kr_rest.private_key import get_private_key

FLAGS = flags.FLAGS

class TradeSide(Enum):
    BUY = 0
    SELL = 1

class SignalCalculator(object):
  def __init__(self, queue_size = 15, bar_percentage = 0.5, opp_bar_percentage = 0.2):
    self._kqueue_size = queue_size
    self._kbar_percentage = bar_percentage
    self._kopp_bar_percentage = opp_bar_percentage
    self.signal_queue = deque(0 for i in range(self._kqueue_size))
    self.plus_signal_cnt = 0
    self.minus_signal_cnt = 0
  
  def clear(self):
    self.signal_queue = deque(0 for i in range(self._kqueue_size))
    self.plus_signal_cnt = 0
    self.minus_signal_cnt = 0

  def add_signal(self, signal):
    old_signal = self.signal_queue.popleft()
    if old_signal > 0:
      self.plus_signal_cnt -= 1
    elif old_signal < 0:
      self.minus_signal_cnt -= 1
    
    if signal > 0:
      self.plus_signal_cnt += 1
    elif signal < 0:
      self.minus_signal_cnt += 1
    
    self.signal_queue.append(signal)
  
  def has_plus_signal(self, in_opp):
    if in_opp:
      return float(self.plus_signal_cnt) / float(self._kqueue_size) > self._kopp_bar_percentage
    else:
      return float(self.plus_signal_cnt) / float(self._kqueue_size) > self._kbar_percentage
  
  def has_minus_signal(self, in_opp):
    if in_opp:
      return float(self.minus_signal_cnt) / float(self._kqueue_size) > self._kopp_bar_percentage
    else:
      return float(self.minus_signal_cnt) / float(self._kqueue_size) > self._kbar_percentage

  def get_plus_percentage(self):
    return float(self.plus_signal_cnt) / float(self._kqueue_size)
  
  def get_minus_percentage(self):
    return float(self.minus_signal_cnt) / float(self._kqueue_size)

class SingleProductSubStrategyArbBase(object):
  def __init__(self, model_profile, dry_run, logger, strategy_logger, latency_recorder, parent):
    self._dry_run = dry_run
    self._logger = logger
    self._strategy_logger = strategy_logger
    self._latency_recorder = latency_recorder
    self._parent = parent
    config = model_profile.config_dict
    self._config = config
    self._trade_subreq = model_profile.trade_subreq
    self._trade_product = model_profile.trade_product
    self._ref_subreq = model_profile.ref_subreq
    self._ref_product = model_profile.ref_product
    assert len(self._ref_subreq) == len(self._ref_product)

    self._edge = None
    self._spread = None
    self._spread_hard = None
    self._pull_edge = None

    self._bbo_protection = config.get('bbo_protection', False)
    self._edge = config['edge_bp'] / 10000.

    products = self._ref_product + to_list(self._trade_product)
    self._bookmap = BookMap(products, logger=self._logger)

    tick = get_holder_from_product(self._trade_product).product_info.first_tick_size
    self._pricer = IndexPricer(self._config, tick)
    self._pos_lean_pricer = PositionLeanPricer(min_pos=config['min_pos'],
                                               max_pos=config['max_pos'],
                                               lot_size=config['lot_size'],
                                               lean_edge_bp=config.get('lean_edge_bp', 0))

    self._last_book_write_ts = get_timestamp()
    self._last_binance_book_ts = 0
    self._last_uniswap_book_ts = 0
    self._last_binance_ask0 = 0.0
    self._last_binance_bid0 = 0.0
    self._last_uniswap_ask0 = 0.0
    self._last_uniswap_bid0 = 0.0
    self._kmax_diff_ms = int(self._config.get('max_diff_ms', 500))

    self._kgas_fee = float(self._config.get('gas_fee', 0.5))
    self.reserve_pos = float(self._config.get('reserve', 0.5))
    self.max_pos = float(self._config.get('max_pos', 0.9))
    self.min_pos = float(self._config.get('min_pos', 0.1))
    self.current_pos = self.reserve_pos
    self.lot_size = float(self._config.get('lot_size', 0.1))

    self._executor = None
    self._exit = False
    self._is_buy_submitted = False
    self._is_sell_submitted = False

  def set_exit(self):
    self._exit = True

  def prepare_base(self, feed_subsystem):
    assert feed_subsystem is not None
    product = self._trade_product
    subreq = self._trade_subreq
    trade_feed_sub_request = FeedSubscriptionRequest.create(to_list(product), subreq)
    feed_subsystem.subscribe_book(trade_feed_sub_request, functools.partial(
        self.on_book, self._trade_product, self._trade_subreq))
    for product, sub_req in zip(self._ref_product, self._ref_subreq):
      feed_sub_request = FeedSubscriptionRequest.create(to_list(product), sub_req)
      feed_subsystem.subscribe_book(
          feed_sub_request, functools.partial(self.on_book, product, sub_req))

    feed_subsystem.subscribe_trade(trade_feed_sub_request, functools.partial(
        self.on_trade, self._trade_product, self._trade_subreq))
    for product, sub_req in zip(self._ref_product, self._ref_subreq):
      feed_sub_request = FeedSubscriptionRequest.create(to_list(product), sub_req)
      feed_subsystem.subscribe_trade(
          feed_sub_request, functools.partial(self.on_trade, product, sub_req))
    return True

  def on_book_base(self, product, sub_req, book):
    if self._exit:
      return False

    if product == self._trade_product and self._executor is not None:
      book_ts = book.timestamp
      if book_ts - self._last_book_write_ts >= 5 * 10**9:
        self._last_book_write_ts = book_ts
        best_book_entry = BestBookEntry(symbol=product.symbol,
                                        fetched_ts=book_ts,
                                        ask0=BookEntry(price_float=book.ask0().price),
                                        bid0=BookEntry(price_float=book.bid0().price))
        self._strategy_logger.write_best_book_entry(
            best_book_entry, account_request=self._executor.og.og_logger.request)

    if self._latency_recorder is not None:
      account_request = AccountRequestProto(market_type=sub_req.market_type,
                                            exchange=sub_req.exchange,
                                            api_version=sub_req.api_version)
      self._latency_recorder.begin(LatencyProto.FEED_LATENCY)
      self._latency_recorder.set_time(LifeOfSignal.RAW_FEED_PARSE_STARTED,
                                      account_request=account_request,
                                      timestamp=book.timestamp)
      self._latency_recorder.set_time(
          LifeOfSignal.ON_BOOK_FEED,
          account_request=account_request,
      )
      self._latency_recorder.end()
      self._latency_recorder.begin()
      self._latency_recorder.set_time(LifeOfSignal.RAW_FEED_PARSE_STARTED,
                                      account_request=account_request,
                                      timestamp=book.timestamp)
      self._latency_recorder.set_time(
          LifeOfSignal.ON_BOOK_FEED,
          account_request=account_request,
      )

    self._bookmap.set_book(product, book)

    # Check book freshness and sanity
    if not self._bookmap.is_book_ready() or not self._bookmap.is_book_sane():
      return False

    ref_book = [self._bookmap.get_book(product) for product in self._ref_product]
    trade_book = self._bookmap.get_book(self._trade_product)
    #self._pricer.update(ref_book, trade_book)

    
    if product.exchange == 'Uniswap':
      if book.timestamp - self._last_uniswap_book_ts >= 2 * 10 ** 4:
        self._last_uniswap_book_ts = book.timestamp
        self._last_uniswap_ask0 = book.ask0().price
        self._last_uniswap_bid0 = book.bid0().price
        self._logger.info('%s %s Book product: %s, askp: %s, bidp: %s' % (
          to_datetime(book.timestamp), book.timestamp, product.symbol, book.ask0().price, book.bid0().price))
      else:
        return False
    elif product.exchange == 'Binance':
      if book.timestamp - self._last_binance_book_ts >= 500 * 10 ** 6:
        self._last_binance_book_ts = book.timestamp
        self._last_binance_ask0 = book.ask0().price
        self._last_binance_bid0 = book.bid0().price
        self._logger.info('%s %s Book product: %s, askp: %s, bidp: %s' % (
          to_datetime(book.timestamp), book.timestamp, product.symbol, book.ask0().price, book.bid0().price))
      else:
        return False
    #if self._executor is None or not self._pricer.ready:
    #  return False
    if self._executor is None:
      return False
    return True

  def on_trade_base(self, product, sub_req, trade):
    if product.exchange == 'Uniswap':
      self._logger.info('%s Trade product: %s, price: %s, qty: %s, side: %s' % (
        to_datetime(trade.timestamp), product.symbol, trade.price, trade.qty, trade.side))
    return True

  def on_og_reset(self, *, order_gateway):
    self._logger.info('Intializing executor...')
    executor_params = convert_executor_config_from_dict(self._trade_product.symbol, self._config)
    self._executor = construct_agg_executor(self._trade_subreq,
                                            executor_params,
                                            order_gateway,
                                            self._logger,
                                            latency_recorder=self._latency_recorder)
    self._strategy_logger.write_executor_config(executor_params)

  def prepare_process(self, feed_subsystem):
    return

  def on_book_process(self, product, sub_req, book):
    return

  def on_trade_process(elf, product, sub_req, trade):
    return

  def prepare(self, feed_subsystem):
    if not self.prepare_base(feed_subsystem):
      return
    self.prepare_process(feed_subsystem)

  def on_book(self, product, sub_req, book):
    if not self.on_book_base(product, sub_req, book):
      return
    self.on_book_process(product, sub_req, book)

  def on_trade(self, product, sub_req, trade):
    if not self.on_trade_base(product, sub_req, trade):
      return
    self.on_trade_process(product, sub_req, trade)

class SimpleArbStatisticPriceWindow(SingleProductSubStrategyArbBase):
  def __init__(self, model_profile, dry_run, logger, strategy_logger, latency_recorder, parent):
    super().__init__(model_profile, dry_run, logger, strategy_logger, latency_recorder, parent)
    self.last_processed_uniswap_ts = 0
    self._kgas_fee = 0.5
    self._kprice_diff_bar = 0.1
    self._ksignal_cnt_bar = 5
    self.plus_signal_cnt = 0
    self.minus_signal_cnt = 0
    self.total_diff = 0.0

    self.start_uniswap_ts = 0
    self.start_uniswap_ask0 = 0.0
    self.start_uniswap_bid0 = 0.0
    self.start_binance_ask0 = 0.0
    self.start_binance_bid0 = 0.0
    self.last_uniswap_ts = 0
    self.last_uniswap_ask0 = 0.0
    self.last_uniswap_bid0 = 0.0
    self.last_binance_ask0 = 0.0
    self.last_binance_bid0 = 0.0
  
  def process_current_signal(self):
    if self.plus_signal_cnt >= self._ksignal_cnt_bar:
      self._logger.info('Price diff[plus pos]: start from:%s, uniswap_ask0: %s, binance_bid0: %s, diff:%s' % (
            to_datetime(self.start_uniswap_ts), self.start_uniswap_ask0, self.start_binance_bid0, self.start_binance_bid0 - self.start_uniswap_ask0))
      self._logger.info('Price diff[plus pos]: end at:%s, uniswap_ask0: %s, binance_bid0: %s, diff:%s' % (
            to_datetime(self.last_uniswap_ts), self.last_uniswap_ask0, self.last_binance_bid0, self.last_binance_bid0 - self.last_uniswap_ask0))
      self._logger.info('Price diff[plus pos]: avg diff:%s' % (self.total_diff / float(self.plus_signal_cnt)))
    elif self.minus_signal_cnt >= self._ksignal_cnt_bar:
      self._logger.info('Price diff[minus pos]: start from:%s, uniswap_bid0: %s, binance_ask0: %s, diff:%s' % (
            to_datetime(self.start_uniswap_ts), self.start_uniswap_bid0, self.start_binance_ask0, self.start_uniswap_bid0 - self.start_binance_ask0))
      self._logger.info('Price diff[minus pos]: end at:%s, uniswap_bid0: %s, binance_ask0: %s, diff:%s' % (
            to_datetime(self.last_uniswap_ts), self.last_uniswap_bid0, self.last_binance_ask0, self.last_uniswap_bid0 - self.last_binance_ask0))
      self._logger.info('Price diff[minus pos]: avg diff:%s' % (self.total_diff / float(self.minus_signal_cnt)))
      

  def set_last_info(self, uniswap_ts, uniswap_ask0, uniswap_bid0, binance_ask0, binance_bid0):
    self.last_uniswap_ts = uniswap_ts
    self.last_uniswap_ask0 = uniswap_ask0
    self.last_uniswap_bid0 = uniswap_bid0
    self.last_binance_ask0 = binance_ask0
    self.last_binance_bid0 = binance_bid0

  def set_start_info(self, uniswap_ts, uniswap_ask0, uniswap_bid0, binance_ask0, binance_bid0):
    self.start_uniswap_ts = uniswap_ts
    self.start_uniswap_ask0 = uniswap_ask0
    self.start_uniswap_bid0 = uniswap_bid0
    self.start_binance_ask0 = binance_ask0
    self.start_binance_bid0 = binance_bid0

  def process_new_tick(self, uniswap_ts, uniswap_ask0, uniswap_bid0, binance_ask0, binance_bid0):
    if uniswap_ts == self.last_processed_uniswap_ts:
      return
    self.last_processed_uniswap_ts = uniswap_ts
    self._logger.info('tick:%s' % (to_datetime(uniswap_ts)))
    if uniswap_ask0 < binance_bid0 - self._kprice_diff_bar:
      if self.plus_signal_cnt > 0:
        self.plus_signal_cnt += 1
        self.total_diff += binance_bid0 - uniswap_ask0
      else:
        self.process_current_signal()
        self.plus_signal_cnt = 1
        self.minus_signal_cnt = 0
        self.total_diff = binance_bid0 - uniswap_ask0
        self.set_start_info(uniswap_ts, uniswap_ask0, uniswap_bid0, binance_ask0, binance_bid0)
      self.set_last_info(uniswap_ts, uniswap_ask0, uniswap_bid0, binance_ask0, binance_bid0)
    elif uniswap_bid0 > binance_ask0 + self._kprice_diff_bar:
      if self.minus_signal_cnt > 0:
        self.minus_signal_cnt += 1
        self.total_diff += uniswap_bid0 - binance_ask0
      else:
        self.process_current_signal()
        self.minus_signal_cnt = 1
        self.plus_signal_cnt = 0
        self.total_diff = uniswap_bid0 - binance_ask0
        self.set_start_info(uniswap_ts, uniswap_ask0, uniswap_bid0, binance_ask0, binance_bid0)
      self.set_last_info(uniswap_ts, uniswap_ask0, uniswap_bid0, binance_ask0, binance_bid0)
    else:
      self.process_current_signal()
      self.minus_signal_cnt = 0
      self.plus_signal_cnt = 0
      self.total_diff = 0.0

  def on_book_process(self, product, sub_req, book):
    if product.exchange == 'Uniswap':
      if abs(book.timestamp - self._last_binance_book_ts) <= self._kmax_diff_ms * 10 ** 6:
        self.process_new_tick(book.timestamp, book.ask0().price, book.bid0().price, self._last_binance_ask0, self._last_binance_bid0)

    elif product.exchange == 'Binance':
      if abs(book.timestamp - self._last_uniswap_book_ts) <= self._kmax_diff_ms * 10 ** 6:
        self.process_new_tick(self._last_uniswap_book_ts, self._last_uniswap_ask0, self._last_uniswap_bid0, book.ask0().price, book.bid0().price)

class SimpleArbOrderTestSubStrategy(SingleProductSubStrategyArbBase):
  def __init__(self, model_profile, dry_run, logger, strategy_logger, latency_recorder, parent):
    super().__init__(model_profile, dry_run, logger, strategy_logger, latency_recorder, parent)

  def on_book_process(self, product, sub_req, book):
    if product != self._trade_product:
      return
    askp, bidp = book.ask0().price, book.bid0().price
    
    if FLAGS.op_buy:
      if not self._is_buy_submitted:
        self._is_buy_submitted = True
        self._logger.info('Submit Order[BUY]: %s, buy: %s' % (
            self._trade_product.symbol, askp))
        result = self._executor.submit_agg_order(
            order_side=OrderSide.BUY,
            order_price=askp * 1.01,
            order_qty=self._executor.config.lot_size)
        if not result:
          self._logger.info('Order Failed[BUY]!!')
        else:
          self._logger.info('Arb Order[BUY]: %s, buy: %s' % (
            self._trade_product.symbol, askp))
    else:
      if not self._is_sell_submitted:
        self._is_sell_submitted = True
        self._logger.info('Submit Order[SELL]: %s, sell: %s' % (
            self._trade_product.symbol, bidp))
        result = self._executor.submit_agg_order(
            order_side=OrderSide.SELL,
            order_price=bidp * 0.99,
            order_qty=self._executor.config.lot_size)
        if not result:
          self._logger.info('Order Failed[SELL]!!')
        else:
          self._logger.info('Arb Order[SELL]: %s, sell: %s' % (
              self._trade_product.symbol, bidp))
    
    return

class SimpleArbStrategy(UnaryMultifeedStrategyBase):
  def __init__(self, strat_config, dry_run=True, exit_after_min=None, logger=None):
    self._logger = logger or logging.getLogger('SimpleArbStrategy')
    assert isinstance(strat_config, PassUnhedgeStrategyConfig)
    self._config = strat_config
    self._set_traits(self._config.trade_subreq)
    self._exit_after_min = exit_after_min
    super().__init__(products=self._config.get_products(),
                     currencies=self._config.get_currencies(),
                     logger=self._logger)

    self._book = BookMap(self._products, logger=self._logger)

    self._reserve_map = self._gen_reserve_map()
    printer_cls = get_pnl_balance_printer_cls(self._config.trade_subreq)
    self._printer = printer_cls(self._products, self._book, self._reserve_map, logger=self._logger)

    self._fill_dumper = FillLogDumper(self._config.trade_subreq)

    self._order_canceled_after_og_ready = True
    self._exit_attempt = 0
    self._exit_executor = None
    self._strategy_logger = StrategyLogProvider(
        self._config.strategy_request, log_root=os.path.expanduser('~/data/strat_slim_proto_log'))
    self._strategy_logger.write_request()
    if strat_config.config['common'].get('enable_telemetry'):
      self._latency_recorder = LatencyRecorder('life_of_signal', self._strategy_logger)
      self._logger.info('telemetry enabled!')
    else:
      self._latency_recorder = None
      self._logger.info('telemetry disabled!')

    self._single_product_sub_strategies = []
    for profile in self._config.model_profile.values():
      self._single_product_sub_strategies.append(
          SimpleArbOrderTestSubStrategy(model_profile=profile,
                                   dry_run=dry_run,
                                   logger=self._logger,
                                   strategy_logger=self._strategy_logger,
                                   latency_recorder=self._latency_recorder,
                                   parent=self))

  @property
  def config(self):
    return self._config

  @property
  def strategy_logger(self):
    return self._strategy_logger

  def _gen_reserve_map(self):
    reserve_map = {}
    if self._config.trade_subreq.market_type == 'Spot':
      for profile in self._config.model_profile.values():
        currency = profile.trade_product.base.currency
        min_pos = profile.config_dict['min_pos']
        max_pos = profile.config_dict['max_pos']
        reserve = 0.5 * (min_pos + max_pos)
        reserve_map[currency] = reserve
    return reserve_map

  def dump_pnl_balance(self):
    self._printer.print_pnl_balance()
    pnl_balances = self._printer.calculate_pnl_balance()
    if pnl_balances is not None:
      for pnl_balance in pnl_balances:
        self._strategy_logger.write_pnl_balance(pnl_balance=pnl_balance, quote=None, subreq_id=None)
    if self._reserve_map:
      self._strategy_logger.write_reserve(
        reserve_as_proto(self._config.trade_subreq, self._reserve_map),
        account_request=self.order_gateway.og_logger.request)

  def prepare(self):
    for profile in self.config.model_profile.values():
      product = profile.trade_product
      feed_sub_request = FeedSubscriptionRequest.create(to_list(product), profile.trade_subreq)
      self.feed_subsystem.subscribe_book(feed_sub_request, functools.partial(self.on_book, product))
    for strat in self._single_product_sub_strategies:
      strat.prepare(self.feed_subsystem)
    # Start dumping pnl balance every 30 seconds
    PeriodicCallback(self.dump_pnl_balance, 30 * 1000).start()
    if self._exit_after_min is not None:
      self.register_exit(datetime.timedelta(minutes=self._exit_after_min))

  def on_og_reset(self):
    if not self._order_canceled_after_og_ready:
      self.order_gateway.cancel_all()
      self._logger.info('Orders canceled after OGs are ready.')
      self._order_canceled_after_og_ready = True

    self._printer.register_order_gateway(self.order_gateway)
    for strat in self._single_product_sub_strategies:
      strat.on_og_reset(order_gateway=self.order_gateway)
    self.order_gateway.register_fill_callback(self._fill_dumper.dump_fill)

    self._exit_executor = SimpleCancelAllExecutor()

    if self._reserve_map:
      self._strategy_logger.write_reserve(reserve_as_proto(self._config.trade_subreq,
                                                           self._reserve_map),
                                          account_request=self.order_gateway.og_logger.request)

    # TODO(chensili): Add OkexFutures limit error check

  def on_book(self, product, book):
    self._book.set_book(product, book)

  def signal_handler(self, sig, frame):
    self._logger.warning('Caught signal: %s', sig)
    self._ioloop.add_callback_from_signal(self.on_exit)

  def register_exit(self, timedelta=None):
    if timedelta is None:
      self._ioloop.add_callback(self.on_exit)
    else:
      self._ioloop.add_timeout(timedelta, self.on_exit)

  def on_exit(self):
    for strat in self._single_product_sub_strategies:
      strat.set_exit()

    self._exit_attempt += 1
    if self._exit_attempt > 5:
      self._ioloop.add_callback(self._ioloop.stop)

    finished = True
    if self._exit_executor is not None:
      ogs = to_list(self.order_gateway)
      self._logger.info('Exit callback executed.')
      finished = self._exit_executor.cancel_all_on_exit(ogs)

    if finished:
      self._ioloop.add_callback(self._ioloop.stop)
    else:
      timeout = datetime.timedelta(seconds=2)
      self._ioloop.add_timeout(timeout, self.on_exit)


def main(argv):
  init_og_after_min = 2

  strat_config = PassUnhedgeStrategyConfig(load_clean_json(FLAGS.config_filename))
  strategy = SimpleArbStrategy(strat_config,
                               dry_run=FLAGS.dry_run,
                               exit_after_min=FLAGS.exit_after_min)
  signal.signal(signal.SIGTERM, strategy.signal_handler)
  signal.signal(signal.SIGINT, strategy.signal_handler)

  feed_checker_config = strat_config.feed_checker_config
  og_config_dict = {'owner': FLAGS.og_config_name}  # wallet address
  return strategy.run_live(strategy=strategy,
                           on_order_gateway_reset_callback=strategy.on_og_reset,
                           og_config_name=None,
                           og_params=strategy.config.og_params,
                           init_order_gateway_after=datetime.timedelta(seconds=init_og_after_min),
                           feed_checker_config=feed_checker_config,
                           og_log_callback=strategy.strategy_logger.write_og_log,
                           slow_callback_duration=0.01,
                           og_config_dict=og_config_dict)


if __name__ == '__main__':
  flags.DEFINE_string('og_config_name', None, 'og_config_name')

  flags.DEFINE_string('config_filename', '', 'config_filename')

  flags.DEFINE_integer('exit_after_min', 1440, 'exit_after_min')

  flags.DEFINE_boolean('op_buy', False, 'op_buy')

  flags.DEFINE_boolean('dry_run', False, 'dry_run')

  flags.DEFINE_float('slow_callback_duration', None, 'slow_callback_duration')

  logging.basicConfig(level='INFO', format='%(levelname)s %(asctime)s %(name)s] %(message)s')
  app.run(main)
